// ==UserScript==
// @name         漂流瓶
// @namespace    https://www.thiswebsitewillselfdestruct.com/
// @version      1.3
// @description  沿着岸边，切开雨线，沉默的漂流瓶浮于水面。随机查看一条来自世界各地的留言！数据来自一个有趣的网站：https://www.thiswebsitewillselfdestruct.com/
// @author       一语子
// @include      *
// @icon         https://gitee.com/yiyuzi/image/raw/master/img/yiyuzi/piaoliuping.png
// @require      https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js
// @connect      thiswebsitewillselfdestruct.com
// @grant        GM_xmlhttpRequest
// @grant        GM_registerMenuCommand
// @grant        GM_unregisterMenuCommand
// @grant        GM_getValue
// @grant        GM_setValue
// ==/UserScript==

'use strict';
// console.log("漂流瓶 start");

var menu_ALL = [
    ['menu_ball_pos_top', '球初始位置（距上）', '20', 'input'],
    ['menu_ball_pos_left', '球初始位置（距左）', '80', 'input'],
    ['menu_ball_height', '球直径', '40', 'input'],
    ['menu_letter_border_display', '正文边框是否显示', true, 'checkbox'],
    ['menu_letter_border_width', '正文边框宽度', '4', 'input'],
    ['menu_letter_border_color', '正文边框颜色', '#87CEFA', 'input'],
    ['menu_letter_font_size', '正文字号', '15', 'input'],
    ['menu_letter_pos_top', '正文初始位置（距上）', '10', 'input'],
    ['menu_letter_pos_left', '正文初始位置（距左）', '10', 'input'],
    ['menu_letter_width', '正文宽度', '60', 'input'],
    ['menu_letter_is_can_move', '正文是否能拖动', true, 'checkbox'],
    ['menu_countdown_display', '下班倒计时是否显示(刷新页面)', true, 'checkbox'],
    ['menu_countdown_time', '下班时间', '17:30', 'input']
], menu_ID = [];

ballInit();
var letterLeft, letterTop;

// 设置
function menu_setting(title, line, menu) {
    let _br = '', _html = `<style>
        #all_light { /*整个弹窗的页面*/
            opacity: 0.8; /*透明度*/
            width: 100%; /*宽度*/
            height: 100%; /*高度，不能百分百*/
            background: #000; /*背景色*/
            position: fixed;
            top: 0;
            left: 0; /*定位*/
            display: block; /*隐藏*/
            z-index: 2001; /*覆盖*/
        }
        #contes { /* 弹框的页面*/
            z-index: 2002;
            position: fixed;
            top: 10%;
            left: 50%;
            -webkit-transform: translate(-50%, 0%);
            -moz-transform: translate(-50%, 0%);
            -ms-transform: translate(-50%, 0%);
            -o-transform: translate(-50%, 0%);
            transform: translate(-50%, 0%);
            width: auto;
            min-width: 40%;
            max-width: 90%;
            height: auto;
            max-height: 80%;
            min-height: 40%;
            color: #535353;
            background-color: #fff;
            border-radius: 3px;
            overflow-x:hidden;
            overflow-y:auto;
            font-size: 15px !important;
        }
        .ballInput{
            margin: 3px;
            outline-style: none;
            border: none;
            box-shadow: 0 0 3px #696969,0 0 3px #696969;
            padding: 2px;
        }
        .ballInput:focus{
            border-color: #66afe9;
            outline: 0;
            -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(30,144,255,.6);
            box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(30,144,255,.6)
        }
        .ballLabel{
            width: auto;
            min-width: 40%;
            display: inline-block;
            cursor: default;
        }
        #closeBtn, #defaultBtn, #submitBtn{
            margin: 10px;
            padding: 5px;
            border-radius: 5px;
            background: #4B98F0;
            color: #fff;
            cursor: pointer;
            min-width: 80px;
        }</style>
        <div id="contes">
        <div><div style="padding: 10px 0px 5px 10px; font-size:20px">${title}</div>
        <hr> <form id="ballSettingForm" style="margin: 5% 10% 5% 10%;">
        `
    if (line) _br = '<br>'
    for (let i=0; i<menu.length; i++) {
        let v = GM_getValue(menu[i][0]) ? GM_getValue(menu[i][0]) : menu[i][2];
        if (menu[i][3] == 'checkbox' && GM_getValue(menu[i][0])){
            _html += `<label class ="ballLabel">${menu[i][1]}</label><input id="${menu[i][0]}" class="ballInput" name="${menu[i][0]}" type="${menu[i][3]}" value="${v}" checked>${_br}`
        }else {
            _html += `<label class ="ballLabel">${menu[i][1]}</label><input id="${menu[i][0]}" class="ballInput" name="${menu[i][0]}" type="${menu[i][3]}" value="${v}">${_br}`
        }
    }
    _html += `<input id="closeBtn" type="button" value="关闭"><input id="defaultBtn" type="button" value="恢复默认值"><input id="submitBtn" type="button" value="应用"> </form> </div></div><div id="all_light"></div>${_br}`
    document.body.insertAdjacentHTML('beforeend', _html); // 插入网页末尾
    setTimeout(function() { // 延迟 100 毫秒，避免太快
        // 关闭按钮 点击事件
        $('#closeBtn').bind('click', closeSetting);
        // 点击周围空白处 = 点击关闭按钮
        $("#all_light").bind('click', closeSetting);
        $("#defaultBtn").bind('click', function(){
            for (let i=0;i<menu.length;i++){
                $("#"+menu[i][0]).val(menu[i][2]);
            };
        });
        $('#submitBtn').bind('click', function(){
            for (let i=0; i<menu.length; i++) {
                if (menu[i][3] == 'checkbox'){
                    GM_setValue(menu[i][0], $("#"+menu[i][0]).is(":checked"));
                }else {
                    GM_setValue(menu[i][0], $("#"+menu[i][0]).val());
                }
            }
            setBallStyle();
        });
    }, 100)
}

function closeSetting(){
    $("#all_light").remove();
    $('#contes').remove();
}

function ballInit(){
    for (let i=0;i<menu_ALL.length;i++){ // 如果读取到的值为 null 就写入默认值
        if (GM_getValue(menu_ALL[i][0]) == null){GM_setValue(menu_ALL[i][0], menu_ALL[i][2])};
    }
    GM_registerMenuCommand("设置", function(){menu_setting("设置", true, menu_ALL)});

    let letterBallCountdown = "<div id=\"letterBallCountdownId\">咕</div>";
    let letterBallImg = "<img id=\"letterBallImgId\" src=\"\"  alt=\"漂流瓶\" />";

    if (GM_getValue("menu_countdown_display")) {
        $("body").append("<div id=\"letterBallId\"><div id=\"letterBallRelativeId\">" + letterBallCountdown + letterBallImg +"</div></div>");
        setBallStyle();
        suspensionBall('letterBallId');
        let countDownInterval = setInterval(() => {
            // 不能靠计时器来确定剩余时间，计时器的执行可能与实际时间有一点误差，多次累积起来误差就大了。
            let date = new Date();
            let now = date.getHours();
            let countdown_time = GM_getValue("menu_countdown_time");
            let hours = countdown_time.split(":")[0] - date.getHours();
            let minutes = countdown_time.split(":")[1] - date.getMinutes()-1;
            if (minutes < 0) {
                minutes += 60;
                hours -= 1;
            }
            if (hours < 0) {
                $("#letterBallCountdownId").text("下班啦！");
                clearInterval(countDownInterval);
            } else {
                let seconds = 60 - date.getSeconds();
                $("#letterBallCountdownId").text(hours.toString().padStart(2,'0')+":"+minutes.toString().padStart(2,'0')+":"+seconds.toString().padStart(2,'0'));
            }
        }, 1000);
    }else{
        $("body").append("<div id=\"letterBallId\"><div id=\"letterBallRelativeId\">" + letterBallImg + "</div></div>");
        setBallStyle();
        suspensionBall('letterBallId');
    }
}

function setBallStyle(){
    $(".ballStyle").remove();
    $("head").append("<link href=\"https://fonts.font.im/css?family=Open+Sans\" rel=\"stylesheet\">");
    $("body").append("<style class=\"ballStyle\">" +
                     "#letterBallId, #letterBallRelativeId, #letterBallCountdownId, #letterBallImgId {" +
                     "width: " + GM_getValue("menu_ball_height") + "px;" +
                     "height: " + GM_getValue("menu_ball_height") + "px;" +
                     "border-radius: 50%;" +
                     "}" +
                     "#letterBallId{" +
                     "position:fixed;" +
                     "z-index: 2010;" +
                     "transform: translate3d(50%, 50%, 0);" +
                     "cursor: pointer;" +
                     "top: " + GM_getValue("menu_ball_pos_top") + "%;" +
                     "left: " + GM_getValue("menu_ball_pos_left") + "%;" +
                     "}" +
                     "#letterBallRelativeId {" +
                     "position:relative;" +
                     "z-index: 2008;" +
                     "transform: translate3d(0%, 0%, 0);" +
                     "pointer-events: auto;" +
                     "top: 0;" +
                     "left: 0;" +
                     "}" +
                     "#letterBallImgId{" +
                     "position:absolute;" +
                     "z-index: 2007;" +
                     "transform: translate3d(0%, 0%, 0);" +
                     "pointer-events: auto;" +
                     "top: 0;" +
                     "left: 0;" +
                     "transition-property: opacity;" +
                     "transition-duration: .25s;" +
                     "}" +
                     "#letterBallCountdownId {" +
                     "position:absolute;" +
                     "z-index: 2008;" +
                     "font-size: " + (GM_getValue("menu_ball_height")/3) + "px;" +
                     "pointer-events: auto;" +
                     "width: auto;" +
                     "height: auto;" +
                     "top: 50%;" +
                     "left: 50%;" +
                     "transform: translate(-50%,-50%);" +
                     "transition-property: opacity;" +
                     "transition-duration: .25s;" +
                     "opacity:0%;" +
                     "}" +
                     "#letterBallCountdownId:hover~#letterBallImgId {" +
                     "opacity:20%;" +
                     "}" +
                     "#letterBallCountdownId:hover {" +
                     "opacity:80%;" +
                     "}" +
                     "#thiswebsitewillselfdestruct {" +
                     //"background: -webkit-gradient(linear,0 0,100% 100%,from(" + GM_getValue("menu_letter_color_from") + "), to(" + GM_getValue("menu_letter_color_to") + "));" +
                     "background: #fff;" +
                     (GM_getValue("menu_letter_border_display") ? "border: " + GM_getValue("menu_letter_border_width") + "mm ridge " + GM_getValue("menu_letter_border_color") + ";" : "") +
                     "width: " + GM_getValue("menu_letter_width") + "%;" +
                     "height: auto;" +
                     "max-height: "+ (92 - GM_getValue("menu_letter_pos_top")) +"%;" +
                     "font-size: " + GM_getValue("menu_letter_font_size") + "px;" +
                     "border-radius: 15px;" +
                     "z-index: 2000;" +
                     "position:fixed;" +
                     "overflow-x:hidden;" +
                     "overflow-y:auto;" +
                     "top: " + GM_getValue("menu_letter_pos_top") + "%;" +
                     "left: " + GM_getValue("menu_letter_pos_left") + "%;" +
                     "text-align: left;" +
                     "background-color: #fcfcfc;" +
//                      "-moz-transition: background-color 500ms linear, color 500ms linear;" +
//                      "-webkit-transition: background-color 500ms linear, color 500ms linear;" +
//                      "-o-transition: background-color 500ms linear, color 500ms linear;" +
//                      "transition: background-color 500ms linear, color 500ms linear;" +
                     "color: black;" +
                     "}" +
//                      "#thiswebsitewillselfdestruct:hover {" +
//                      "background-color: #111;" +
//                      "color: gray;" +
//                      "}" +
                     "#thiswebsitewillselfdestructPre{" +
                     "height: 90%;" +
                     "width: 90%;" +
                     "white-space: pre-wrap; word-wrap: break-word;" +
                     "user-select: text;" +
                     "font-family: 'Open Sans', sans-serif;" +
                     "margin: 15px;" +
                     "background-color: #fcfcfc;" +
                     "}" +
                     "#thiswebsitewillselfdestructPre::-webkit-scrollbar {display: none; background: #fff;}</style>" +
                     "<style class=\"letterScrollStyle\">" +
                     "#thiswebsitewillselfdestruct::-webkit-scrollbar {background: #fff;}" +
                     "#thiswebsitewillselfdestruct::-webkit-scrollbar-thumb {background: #fff; border-radius: 10px;}" +
                     "</style>");
};

function suspensionBall(dragId) {
    var startEvt, moveEvt, endEvt;
    // 判断是否支持触摸事件
    if ('ontouchstart' in window) {
        startEvt = 'touchstart';
        moveEvt = 'touchmove';
        endEvt = 'touchend';
    } else {
        startEvt = 'mousedown';
        moveEvt = 'mousemove';
        endEvt = 'mouseup';
    }
    // 获取元素
    var drag = document.getElementById(dragId);
    // 标记是拖曳还是点击
    var isClick = true;
    // 标记正文是否展开
    var isOpen = false;
    // 标记球的位置
    var disX, disY, left, top, starX, starY;

    drag.addEventListener(startEvt, function (e) {
        // 阻止页面的滚动，缩放
        e.preventDefault();
        // 兼容IE浏览器
        e = e || window.event;
        isClick = true
        // 按下时的坐标
        starX = e.touches ? e.touches[0].clientX : e.clientX;
        starY = e.touches ? e.touches[0].clientY : e.clientY;
        // 相对于拖动元素左上角的位置
        disX = starX - drag.offsetLeft;
        disY = starY - drag.offsetTop;
        // 按下之后才监听后续事件
        document.addEventListener(moveEvt, moveFun);
        document.addEventListener(endEvt, endFun);
    })

    function moveFun(e) {
        // 兼容IE浏览器
        e = e || window.event;
        isClick = false;
        left = (e.touches ? e.touches[0].clientX : e.clientX) - disX;
        top = (e.touches ? e.touches[0].clientY : e.clientY) - disY;
        // 限制拖拽的X范围，不能拖出屏幕
        if (left < 0) {
            left = 0;
        } else if (left > document.documentElement.clientWidth - drag.offsetWidth) {
            left = document.documentElement.clientWidth - drag.offsetWidth;
        }
        // 限制拖拽的Y范围，不能拖出屏幕
        if (top < 0) {
            top = 0;
        } else if (top > document.documentElement.clientHeight - drag.offsetHeight) {
            top = document.documentElement.clientHeight - drag.offsetHeight;
        }
        drag.style.left = left + 'px';
        drag.style.top = top + 'px';
    }

    function endFun(e) {
        document.removeEventListener(moveEvt, moveFun);
        document.removeEventListener(endEvt, endFun);
        if (isClick) {
            if (isOpen){
                $("#thiswebsitewillselfdestruct").remove();
                isOpen = false;
            }else {
                 var letterDiv = document.createElement("div");
                letterDiv.id = "thiswebsitewillselfdestruct";
                var letterPre = document.createElement("pre");
                letterPre.id = "thiswebsitewillselfdestructPre";
                GM_xmlhttpRequest({
                    url:"https://www.thiswebsitewillselfdestruct.com/api/get_letter",
                    method :"GET",
                    onload:function(xhr){
                        var json = JSON.parse(xhr.responseText);
                        letterPre.innerHTML = json.body;
                    }
                });
                $("body").append(letterDiv);
                $("#thiswebsitewillselfdestruct").append(letterPre);
                isOpen = true;
                 if (letterLeft && letterTop){
                    let letter = document.getElementById('thiswebsitewillselfdestruct');
                    letter.style.left = letterLeft + 'px';
                    letter.style.top = letterTop + 'px';
                }
                suspensionLetter('thiswebsitewillselfdestruct');
                $("#thiswebsitewillselfdestructPre").mousedown(function(event){
                    event.stopPropagation();
                });
            }
        }
    }
}

function suspensionLetter(dragId) {
    var startEvt, moveEvt, endEvt;
    // 判断是否支持触摸事件
    if ('ontouchstart' in window) {
        startEvt = 'touchstart';
        moveEvt = 'touchmove';
        endEvt = 'touchend';
    } else {
        startEvt = 'mousedown';
        moveEvt = 'mousemove';
        endEvt = 'mouseup';
    }
    // 获取元素
    var drag = document.getElementById(dragId);
    // 标记是拖曳还是点击
    var isClick = true;
    // 标记位置
    var disX, disY, left, top, starX, starY;

    let t1 = 0;
    let t2 = 0;
    let timer = null; // 定时器

    // 监听滚动事件
    drag.onscroll = function() {
        clearTimeout(timer);
        if(t2 == t1){
            $("body").append("<style class=\"letterScrollTempStyle\">" +
                             "#thiswebsitewillselfdestruct::-webkit-scrollbar-thumb {background: "+GM_getValue("menu_letter_border_color")+";}"+
                             "</style>");
        }
        // 延迟1s消失
        timer = setTimeout(isScrollEnd, 1000);
        t1 = drag.scrollTop;
    }

    function isScrollEnd() {
        t2 = drag.scrollTop;
        if(t2 == t1){
            $(".letterScrollTempStyle").remove();
        }
    }

    if(drag){
        if (GM_getValue("menu_letter_is_can_move")){
            drag.addEventListener(startEvt, startFun);
        }else {
            drag.removeEventListener(startEvt, startFun);
        }
    }

    function startFun(e) {
        // 阻止页面的滚动，缩放
        e.preventDefault();
        // 兼容IE浏览器
        e = e || window.event;
        isClick = true
        // 按下时的坐标
        starX = e.touches ? e.touches[0].clientX : e.clientX;
        starY = e.touches ? e.touches[0].clientY : e.clientY;
        // 相对于拖动元素左上角的位置
        disX = starX - drag.offsetLeft;
        disY = starY - drag.offsetTop;
        // 按下之后才监听后续事件
        document.addEventListener(moveEvt, moveFun);
        document.addEventListener(endEvt, endFun);
    }

    function moveFun(e) {
        // 兼容IE浏览器
        e = e || window.event;
        isClick = false;
        left = (e.touches ? e.touches[0].clientX : e.clientX) - disX;
        top = (e.touches ? e.touches[0].clientY : e.clientY) - disY;
        drag.style.left = left + 'px';
        drag.style.top = top + 'px';
    }

    function endFun(e) {
        document.removeEventListener(moveEvt, moveFun);
        document.removeEventListener(endEvt, endFun);
        letterLeft = left;
        letterTop = top;
    }
}